package com.immediatus.graphics.camera;

public class BoundCamera extends Camera{

    private boolean _isBoundsEnabled;
    private float _boundsMinX;
    private float _boundsMaxX;
    private float _boundsMinY;
    private float _boundsMaxY;
    private float _boundsCenterX;
    private float _boundsCenterY;
    private float _boundsWidth;
    private float _boundsHeight;

    public BoundCamera(final float x_, final float y_, final float w_, final float h_){
        super(x_, y_, w_, h_);
    }

    public BoundCamera(final float x_, final float y_, final float w_, final float h_, final float boundMinX_, final float boundMaxX_, final float boundMinY_, final float boundMaxY_){
        super(x_, y_, w_, h_);
        this.setBounds(boundMinX_, boundMaxX_, boundMinY_, boundMaxY_);
        this._isBoundsEnabled = true;
    }

    public boolean isBoundsEnabled(){
        return this._isBoundsEnabled;
    }

    public void setBoundsEnabled(final boolean boundsEnabled_){
        this._isBoundsEnabled = boundsEnabled_;
    }

    public void setBounds(final float minX_, final float maxX_, final float minY_, final float maxY_){
        this._boundsMinX = minX_;
        this._boundsMaxX = maxX_;
        this._boundsMinY = minY_;
        this._boundsMaxY = maxY_;

        this._boundsWidth = this._boundsMaxX - this._boundsMinX;
        this._boundsHeight = this._boundsMaxY - this._boundsMinY;

        this._boundsCenterX = this._boundsMinX + this._boundsWidth * 0.5f;
        this._boundsCenterY = this._boundsMinY + this._boundsHeight * 0.5f;
    }

    public float getBoundsWidth(){
        return this._boundsWidth;
    }

    public float getBoundsHeight(){
        return this._boundsHeight;
    }

    @Override
    public void setCenter(final float x_, final float y_){
        super.setCenter(x_, y_);

        if (this._isBoundsEnabled){
            this.ensureInBounds();
        }
    }

    protected void ensureInBounds(){
        super.setCenter(this.determineBoundedX(), this.determineBoundedY());
    }

    private float determineBoundedX(){
        if (this._boundsWidth < this.getWidth()){
            return this._boundsCenterX;
        } else{
            final float currentCenterX = this.getCenterX();

            final float minXBoundExceededAmount = this._boundsMinX - this.getMinX();
            final boolean minXBoundExceeded = minXBoundExceededAmount > 0;

            final float maxXBoundExceededAmount = this.getMaxX() - this._boundsMaxX;
            final boolean maxXBoundExceeded = maxXBoundExceededAmount > 0;

            if (minXBoundExceeded){
                if (maxXBoundExceeded){
                    return currentCenterX - maxXBoundExceededAmount + minXBoundExceededAmount;
                } else{
                    return currentCenterX + minXBoundExceededAmount;
                }
            } else{
                if (maxXBoundExceeded){
                    return currentCenterX - maxXBoundExceededAmount;
                } else{
                    return currentCenterX;
                }
            }
        }
    }

    private float determineBoundedY(){
        if (this._boundsHeight < this.getHeight()){
            return this._boundsCenterY;
        } else{
            final float currentCenterY = this.getCenterY();

            final float minYBoundExceededAmount = this._boundsMinY - this.getMinY();
            final boolean minYBoundExceeded = minYBoundExceededAmount > 0;

            final float maxYBoundExceededAmount = this.getMaxY() - this._boundsMaxY;
            final boolean maxYBoundExceeded = maxYBoundExceededAmount > 0;

            if (minYBoundExceeded){
                if (maxYBoundExceeded){
                    return currentCenterY - maxYBoundExceededAmount + minYBoundExceededAmount;
                } else{
                    return currentCenterY + minYBoundExceededAmount;
                }
            } else{
                if (maxYBoundExceeded){
                    return currentCenterY - maxYBoundExceededAmount;
                } else{
                    return currentCenterY;
                }
            }
        }
    }
}
